"""
Posnet server module.
contains the class  "posnet_server"
"""
import sys,socket
import posnet_tcp_server
import threading,thread,time
import logging
from traceback import print_exc
#import cProfile, pstats

class posnet_server(object):
	""" the Posnet server class """
	def __init__(self,listen_address,listen_port,tcp_handler):
		""" initialize the server classes
		    @param listen_address: host address to listen to (default: indicate "")
		    @param listen_port: port to listen to (UDP and TCP are used!) (default: 22000)
		    @param tcp_handler: the handler of tcp messages
		    remember to use a port that is not reserved !		
		"""
		myaddr = (listen_address,listen_port)
		self._tcp_server =  posnet_tcp_server.posnet_tcp_server(myaddr,tcp_handler)

	def shutdown(self):
		try: self._tcp_server.shutdown()
		except: pass

	def serve_forever(self):
		""" make this server to fall into an infinite loop """
		logger = logging.getLogger('posnet.server')
		logger.info("begin Control Plane/Query Plane service (TCP)")
		self._tcp_server.serve_forever()
		logger.info("end Control Plane/Query Plane  service (TCP)")

import posnet_overlay_messages
import posnet_tcp_client
import posnet_overlay_node2

class internet_posnet_underlay:
	def __init__(self):
		self.logger = logging.getLogger('posnet.posnet_underlay')
	def propagate_message(self,message,answer_type = None,sending_id = None):
		src = ""
		if sending_id is not None: src = str(sending_id)
		dst = str(message.target) 
		self.logger.info(src+"\t->\t"+dst)
		return posnet_tcp_client.send_message(message.target,message,answer_type)

# global variable
peer_node = None
server = None
job_executer  = None

import scheduler
import signal
import time
import threading
	
def posnet_server_help_message(out = None):
	import sys
	if out is None: out = sys.stderr
	print >>out,"-"*30
	print >>out,"Create a posnet tcp server" 
	print >>out,"-"*30
	print >>out,"* usage:",sys.argv[0],"port_number [nb_poset_dimensions = 2] | [ posnet_join_node_address posnet_join_node_port]"

if __name__ == "__main__":
	
	socket.setdefaulttimeout(5)
	if len(sys.argv) < 2:
		posnet_server_help_message()
		raise SystemExit
	myHost = socket.gethostbyname(socket.gethostname())
	myPort = int(sys.argv[1])         
	myID = (myHost,myPort)
	#------------------
	# posnet node
	Poset = dict()
	if len(sys.argv) == 3:
		try:
			myNbDimensions = int(sys.argv[2])
			for x in range(myNbDimensions):
				Poset[str(x)] = [1] 
		except:
			pass
#			if sys.argv[2] == "ex1":
#				airports = ["ENF","HEM","HEL","IVL","JOE","KAJ","KEM","KTT","KOK","KAO","LPP","MHQ","MIK","OUL","POR","SVL","SJY","SOT","TKU","VAA","VRK"]
#				airports = ["HEL","JOE","HEM","POR"]
#				Poset["1src"] = airports
#				Poset["2dst"] = airports
#				Poset["3invprice"] = [-199,-399]
#				Poset["4quality"] = [1,2,3]
	elif len(sys.argv) == 4:
		ohost = sys.argv[2]
		oport = int(sys.argv[3])
		Poset = posnet_tcp_client.posnet_ping((ohost,oport))	
	else:
		Poset = {"x":range(1,2),"y":range(1,2)} #,"z":range(7)}
	#-----------------
	# Logging 
	# set up logging to file
	logging.basicConfig(level=logging.INFO, #DEBUG,
			    format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
			    datefmt='%m-%d %H:%M'  #,
			    #filename='posnet_overlay_node2_'+myHost+'_'+str(myPort)+'.log',
			    #filemode='w'
				)
	# define a Handler which writes INFO messages or higher to the sys.stderr
	console = logging.StreamHandler()
	console.setLevel(logging.INFO)
	
	formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') # set a format which is simpler for console use
	console.setFormatter(formatter) # tell the handler to use this format
	#logging.getLogger('').addHandler(console) # add the handler to the root logger
	#---	
	##global job_executer
	job_executer = scheduler.Scheduler("posnet_query_handler")
	job_executer.add_threads(1)
	class queue_instancier:
		def __init__(self,_job_executer):
			self.job_executer = _job_executer
		def enqueue(self, job):
			global job_executer
			def execute_the_job(): self.job_executer(job)
			job_executer.enqueue(execute_the_job)
		def process_queue(self): pass
	##global peer_node
	print "Poset",Poset
	peer_node = posnet_overlay_node2.posnet_overlay_node(Poset,myID,queue_instancier)
	peer_node.set_underlay( internet_posnet_underlay() )
	peer_node.set_debug(False)	
	#---------------------
	# handling messages
	def message_handler(add,buf,client_socket):
		global peer_node
		try:
			message = posnet_overlay_messages.array_to_overlay_message( buf )
			peer_node.receive(message,client_socket)
		except Exception,e:
			print_exc()
	#------------------------
	#*** global server ***
	server = posnet_server("",myPort,message_handler) #,message_handler)
	#----------------
	# catch signal
	def beingkilled(*args):
		global server
		#console.info("signal received: kill scheduler and servers")
		server.shutdown()
	signal.signal(signal.SIGINT,beingkilled)
	#---------
	# Join
	#-------------
	if len(sys.argv) >= 4:
		join_host = sys.argv[2]
		join_address = int(sys.argv[3])
		def send_join_task():
			global peer_node
			time.sleep(1)
			print >>sys.stderr,"send join to node:",(join_host,join_address)
			peer_node.send_join( (join_host,join_address) )
			#
			#server.shutdown()			
		t = threading.Thread(target = send_join_task)
		t.start()
	try:
		#import profile
		#profile.run("server.serve_forever()") 
		server.serve_forever()
	finally:
		job_executer.kill()
		server.shutdown()
